﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace MazeModel
{
    public class MazeLayout
    {
        internal int[,] maze;

        public MazeLayout()
        {
            maze = new int[29, 40];
        }

        public MazeLayout(int i, int j)
        {
            maze = new int[i, j];
        }
        public int getHeight() { return maze.GetLength(0); }
        public int getWidth() { return maze.GetLength(1); }
        public void randomize(int level)
        {
            // 0: tómt, 1: veggur, 2: player, 3: exit, 4: chest
            int[,] newMaze = new int[29, 40];
            for (int i = 0; i < 29; i++)
            {
                for (int j = 0; j < 40; j++)
                {
                    newMaze[i, j] = 1;
                }
            }

            RandomCreator rc = new RandomCreator();
            newMaze = rc.constructMaze(29,40);
            this.maze = newMaze;
        }

        public void loadLevel(string pathToFile)
        {
            List<int> newMazeList = new List<int>();

            string nextLine;
            int i = 0, j = 0;

            try
            {
                StreamReader streamReader = new StreamReader(pathToFile);
                while (!(streamReader.EndOfStream))
                {
                    nextLine = streamReader.ReadLine();
                    j = nextLine.Length;
                    i++;
                    for (int a = 0; a < nextLine.Length; a++)
                    {
                        int nextCell;
                        int.TryParse(nextLine.Substring(a, 1), out nextCell);
                        newMazeList.Add(nextCell);
                    }
                }

                // Búið er að hlaða level inn í newMazeList, auk þess sem i og j
                // innihalda fjölda dálka (j) og lína (i). Þá er bara að rúlla því inn
                LoadLevelFromList(newMazeList, i, j);
            }
            catch
            { 
                // Ef það mistókst að hlaða inn level þá er level randomæsað í staðinn
                this.randomize(0);
            }
        }

        // Hleður inn level af stærðinni [i,j] úr list
        public void LoadLevelFromList(List<int> list, int i, int j) 
        {
            int[,] newMaze = new int[i, j];
            int w = 0;
            for (int ii = 0; ii != i; ii++)
            {
                for (int jj = 0; jj != j; jj++)
                {
                    newMaze[ii, jj] = list[w];
                    w++;
                }
            }
            maze = newMaze;
        }

        // Yes, I know. This is super lame and must die
        public void SaveLevelToTextFile(string pathToFile)
        {
            FileInfo f = new FileInfo(pathToFile);
            StreamWriter w = f.CreateText();
            string nextLine;
            for (int i = 0; i != this.getHeight(); i++)
            {
                nextLine = "";
                for (int j = 0; j != this.getWidth(); j++)
                {
                    nextLine += Convert.ToString(this.getCellAt(i, j)); 
                }
                w.WriteLine(nextLine);
            }
            w.Close();
        }

        // Skilar sellu [i,j] eða 1 ef sellan er ekki til
        public int getCellAt(int i, int j)
        {

            if (i >= 0 && i < this.getHeight() &&
                j >= 0 && j < this.getWidth())
            {
                return maze[i, j];
            }
            else
            {
                return 1;
            }
        }

        // Skilar sellu nálægt [i,j]
        // (1 fyrir ofan, 2 fyrir neðan, 3 til vinstri, 4 til hægri
        public int getCellAdjacent(int i, int j, int dir)
        {
            switch (dir)
            {
                case 1:
                    return this.getCellAt(i - 1, j);
                case 2:
                    return this.getCellAt(i + 1, j);
                case 3:
                    return this.getCellAt(i, j - 1);
                case 4:
                    return this.getCellAt(i, j + 1);
                default:
                    return this.getCellAt(i,j);
            }

        }

        public int getCellAdjacent(int[] pos, int dir)
        {
            return this.getCellAdjacent(pos[0], pos[1], dir);
        }

        public void setCell(int i, int j, int value)
        {
            try
            {
                maze[i, j] = value;
            }
            catch 
            {
                System.Console.WriteLine("Can't write to cell [{0},{1}]", i, j);
            }
        }

        // Forcibly change the size of the maze. This will either truncate or expand the maze
        public void SetSize(int i, int j)
        {
            int[,] newMaze = new int[i,j];
            for (int ii = 0; ii != this.getHeight(); ii++)
                for (int jj = 0; jj != this.getWidth(); jj++)
                    newMaze[ii, jj] = maze[ii, jj];
            maze = newMaze;
        }

    }
}
